package com.corewillsoft.fireflies.util;

/**
 * Class containing different mathematical methods used by physics of the game
 */
public final class MathUtils {

	/**
	 * Returns the circumcircle radius of the square
	 * @param size - height (width) of the square
	 * @return circumcircle radius of this square
	 */
	public static double getCircumcircleRadius(double size) {
		return size / Math.sqrt(2);
	}

	/**
	 * Returns distance between two points specified by (x, y) coordinates
	 * @param x1 - X coordinate of the first point
	 * @param y1 - Y coordinate of the first point
	 * @param x2 - X coordinate of the second point
	 * @param y2 - Y coordinate of the second point
	 * @return distance between the points
	 */
	public static double getDistanceBetweenPoints(double x1, double y1, double x2, double y2){
		return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
	}

	/**
	 * Returns the length of vector specified by 2D coordinates (x; y)
	 * @param x - x-coordinate of the vector
	 * @param y - y-coordinate of the vector
	 * @return length of vector
	 */
	public static double vectorLength(double x, double y) {
		return Math.sqrt(x * x + y * y);
	}

	/**
	 * Calculates the angle between line specified by two points (x1, y1) and (x2, y2) and x-axis
	 * @param x1 - x coordinate of first point
	 * @param y1 - y coordinate of first point
	 * @param x2 - x coordinate of second point
	 * @param y2 - y coordinate of second point
	 * @return angle (in radians) between line and x-axis
	 */
	public static double getLineAngle(double x1, double y1, double x2, double y2) {
		if (x1 == x2) {
			if (y2 > y1) {
				return Math.PI / 2;
			} else {
				return (- Math.PI / 2);
			}
		} else {
			double dx = x2 - x1;
			double dy = y2 - y1;
			double absResult = Math.atan(Math.abs(dy) / Math.abs(dx));

			if ((dx > 0) && (dy > 0)) {
				return absResult;				//I quarter
			} else if ((dx < 0) && (dy > 0)) {
				return Math.PI - absResult;		//II quarter
			} else if ((dx < 0) && (dy < 0)) {
				return (- Math.PI + absResult);	//III quarter
			} else if ((dx > 0) && (dy < 0)) {
				return (- absResult);			//IV quarter
			}
			return absResult;
		}
	}

	/**
	 * Returns ksi coordinate of point in (ksi, nu) system by its known (x, y) coordinates in (x, y) system
	 * @param x - x coordinate in (x, y) system
	 * @param y - y coordinate in (x, y) system
	 * @param phi - angle (in radians) between x-axis and ksi-axis
	 * @return ksi coordinate in (ksi, nu) system
	 */
	public static double getKsiByXY(double x, double y, double phi) {
		return (x * Math.cos(phi) + y * Math.sin(phi));
	}

	/**
	 * Returns nu coordinate of point in (ksi, nu) system by its known (x, y) coordinates in (x, y) system
	 * @param x - x coordinate in (x, y) system
	 * @param y - y coordinate in (x, y) system
	 * @param phi - angle (in radians) between x-axis and ksi-axis
	 * @return nu coordinate in (ksi, nu) system
	 */
	public static double getNuByXY(double x, double y, double phi) {
		return (- x * Math.sin(phi) + y * Math.cos(phi));
	}

	/**
	 * Returns x coordinate of point in (x, y) system by its known (ksi, nu) coordinates in (ksi, nu) system
	 * @param ksi - ksi coordinate in (ksi, nu) system
	 * @param nu - nu coordinate in (ksi, nu) system
	 * @param phi - angle (in radians) between x-axis and ksi-axis
	 * @return x coordinate in (x, y) system
	 */
	public static double getXByKsiNu(double ksi, double nu, double phi) {
		return (ksi * Math.cos(phi) - nu * Math.sin(phi));
	}

	/**
	 * Returns y coordinate of point in (x, y) system by its known (ksi, nu) coordinates in (ksi, nu) system
	 * @param ksi - ksi coordinate in (ksi, nu) system
	 * @param nu - nu coordinate in (ksi, nu) system
	 * @param phi - angle (in radians) between x-axis and ksi-axis
	 * @return y coordinate in (x, y) system
	 */
	public static double getYByKsiNu(double ksi, double nu, double phi) {
		return (ksi * Math.sin(phi) + nu * Math.cos(phi));
	}
}
